﻿Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Xml
Imports System.Xml.Xsl
Imports System.Xml.XPath
Imports System.Runtime.Caching
Imports System.Security.Cryptography
Imports System.IO
Imports Chilkat
Imports System.Configuration
Imports System.Xml.Serialization


Public Class GeneradorSello
    Public Const certificate As String = "aaa010101aaa__csd_01.cer"
    Public Const privatekey As String = "aaa010101aaa__csd_01.key"
    Public Const password As String = "12345678a"

    Public Shared Function ObtenerCadenaOriginal32(ByVal xml As String) As String
        Dim sb As StringBuilder = New StringBuilder()
        Dim xsltPath As String = "\xslt\cfdi32"

        Dim cache As ObjectCache = MemoryCache.Default
        Dim xsl As XslCompiledTransform = New XslCompiledTransform()

        'Dim objecto = New Object()
        'Lock(objecto)
        xsl = New XslCompiledTransform()
        Dim xslSettings = New XsltSettings(False, True)
        xsl.Load(xsltPath, xslSettings, New XmlUrlResolver())
        Dim policy = New CacheItemPolicy()
        Dim paths As List(Of String) = Nothing

        policy.ChangeMonitors.Add(New HostFileChangeMonitor(paths))
        cache.Set(xsltPath, xsl, policy)

        Dim sw As StringWriter = New StringWriter(sb)
        Using stream As StreamReader = New StreamReader(xml)
            Dim xpath As XPathDocument = New XPathDocument(stream)
            xsl.Transform(xpath, Nothing, sw)
        End Using
        Return sb.ToString
    End Function

    Public Shared Function GetCadenaOriginal32(ByVal xml As String) As String
        Dim pathxslt32 = ConfigurationManager.AppSettings.GetValues("pathxslt")
        Dim sb As StringBuilder = New StringBuilder()
        Try
            Using stream As StringReader = New StringReader(xml)
                Dim xpath As XPathDocument = New XPathDocument(stream)

                Dim xslSource As XmlTextReader = New XmlTextReader(String.Format("{0}\cadenaoriginal_3_2.xslt", pathxslt32))
                Dim xsltDoc As XslCompiledTransform = New XslCompiledTransform()
                xsltDoc.Load(xslSource)

                Dim sw As StringWriter = New StringWriter(sb)
                xsltDoc.Transform(xpath, Nothing, sw)

            End Using
        Catch ex As Exception
            Throw ex
        End Try
        Return sb.ToString()
    End Function

    Public Shared Function GetCadenaOriginalRetenciones(ByVal xml As String) As String
        Dim pathxsltRetencion = ConfigurationManager.AppSettings.GetValues("pathxsltRetencion")
        Dim sb As StringBuilder = New StringBuilder()
        Try
            Using stream As StringReader = New StringReader(xml)
                Dim xpath As XPathDocument = New XPathDocument(stream)

                Dim xslSource As XmlTextReader = New XmlTextReader(String.Format("{0}\retenciones.xslt", pathxsltRetencion))
                Dim xsltDoc As XslCompiledTransform = New XslCompiledTransform()
                xsltDoc.Load(xslSource)

                Dim sw As StringWriter = New StringWriter(sb)
                xsltDoc.Transform(xpath, Nothing, sw)

            End Using
        Catch ex As Exception
            Throw ex
        End Try
        Return sb.ToString()
    End Function

    Public Shared Function stampInvoice(ByVal XML As String, ByRef Certificado As String, ByRef noCertificado As String) As String
        Dim stampXML As String = String.Empty
        Try
            Dim CadenaOriginal As String = String.Empty
            Dim result As Boolean = False
            Dim PKey As Chilkat.PrivateKey = New Chilkat.PrivateKey()
            Dim loRsa As Chilkat.Rsa = New Chilkat.Rsa()
            Dim Cert As Chilkat.Cert = New Chilkat.Cert()

            CadenaOriginal = GetCadenaOriginal32(XML)

            result = Cert.LoadFromFile(String.Format("{0}\certificados\{1}", Application.StartupPath, certificate))
            If (result = False) Then
                Throw New Exception("Error al obtener el certificado.")
            End If


            Certificado = Cert.ExportCertPem().ToString().Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Trim().Replace("\r\n", "").Replace("\r", "").Replace("\n", "")
            noCertificado = GetNoCertificado(Cert.SerialNumber)

            result = PKey.LoadPkcs8EncryptedFile(String.Format("{0}\certificados\{1}", Application.StartupPath, privatekey), password)
            If (result = False) Then
                Throw New Exception(String.Format("{0}", PKey.LastErrorText))
            End If

            result = loRsa.UnlockComponent("30-day trial")

            If (result = False) Then
                Throw New Exception(String.Format("{0}", loRsa.LastErrorText))
            End If

            If (loRsa.ImportPublicKey(PKey.GetXml()) = False) Then
                Throw New Exception(String.Format("{0}", loRsa.LastErrorText))
            End If

            loRsa.LittleEndian = False
            loRsa.Charset = "utf-8"
            loRsa.EncodingMode = "base64"

            stampXML = loRsa.SignStringENC(CadenaOriginal, "sha-1")


        Catch ex As Exception
            Throw ex
        End Try
        Return stampXML
    End Function

    Public Shared Function Deserialization(ByVal pObject As Object, ByVal type As Type, ByVal xml As String) As Object
        Try
            Dim string_reader As StringReader
            Dim xml_serializer As New XmlSerializer(type)

            string_reader = New StringReader(xml)
            pObject = xml_serializer.Deserialize(string_reader)
        Catch ex As Exception
            Throw ex
        End Try
        Return pObject
    End Function

    Public Shared Function Serialize32(ByVal pObject As Object, ByVal type As Type) As String
        Try
            Dim XmlizedString As String = Nothing
            Dim memoryStream As MemoryStream = New MemoryStream()
            Dim xs As XmlSerializer = New XmlSerializer(type)
            Using xmlTextWriter As XmlTextWriter = New XmlTextWriter(memoryStream, New UTF8Encoding(False))
                xmlTextWriter.Formatting = Formatting.Indented
                xmlTextWriter.Indentation = 4
                Dim myNamespaces As XmlSerializerNamespaces = New XmlSerializerNamespaces()
                myNamespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance")
                myNamespaces.Add("cfdi", "http://www.sat.gob.mx/cfd/3")

                   
               
                xs.Serialize(xmlTextWriter, pObject, myNamespaces)

                memoryStream = xmlTextWriter.BaseStream
                XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray())

                Return XmlizedString

            End Using

        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Shared Function SerializeRetencion(ByVal pObject As Object, ByVal type As Type) As String
        Try
            Dim XmlizedString As String = Nothing
            Dim memoryStream As MemoryStream = New MemoryStream()
            Dim xs As XmlSerializer = New XmlSerializer(type)
            Using xmlTextWriter As XmlTextWriter = New XmlTextWriter(memoryStream, New UTF8Encoding(False))
                xmlTextWriter.Formatting = Formatting.Indented
                xmlTextWriter.Indentation = 4
                Dim myNamespaces As XmlSerializerNamespaces = New XmlSerializerNamespaces()
                myNamespaces.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance")
                myNamespaces.Add("retenciones", "http://www.sat.gob.mx/esquemas/retencionpago/1")



                xs.Serialize(xmlTextWriter, pObject, myNamespaces)

                memoryStream = xmlTextWriter.BaseStream
                XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray())

                Return XmlizedString

            End Using

        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Shared Function UTF8ByteArrayToString(ByVal characters() As Byte) As String
        Dim constructedString As String = New UTF8Encoding().GetString(characters)
        Return constructedString
    End Function

    Public Shared Function GetNoCertificado(ByVal SerialNumber As String)
        Dim noCertificado As String = String.Empty
        For i As Integer = 0 To SerialNumber.Length
            If (i Mod 2 <> 0) Then
                noCertificado += SerialNumber.Substring(i, 1)
            End If
        Next
        Return noCertificado
    End Function


End Class
